/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 *
 */

import fsExtra from 'fs-extra';
import path from 'path';

import { getJson5Obj } from '../../utils/json-util.js';
import { OhosLogger } from '../../utils/log/ohos-logger.js';

import { NativeCodemodel } from './native-codemodel.js';
import { NativeTarget } from './native-codemodel-target.js';
import { NativeCxxIndex, Reply } from './native-cxx-index.js';

/**
 * 读取cmake生成的codemodel模型, 生成NativeCodemodel
 */
export class GenerateCodemodel {
  private _log: OhosLogger = OhosLogger.getLogger(GenerateCodemodel.name);
  private readonly _codemodel: NativeCodemodel | undefined;
  private readonly reply: string;
  private readonly index: NativeCxxIndex;

  constructor(outputDir: string) {
    this.reply = path.resolve(outputDir, '.cmake', 'api', 'v1', 'reply');
    this.index = this.readIndex();
    this._codemodel = this.generateCodemodel();
  }

  getCodemodel(): NativeCodemodel | undefined {
    return this._codemodel;
  }

  getObjFromIndex<T>(key: string): T | undefined {
    return Object.values(this.index.reply)
      .filter((reply) => reply.kind === key)
      .map<T>((reply) => getJson5Obj(path.resolve(this.reply, reply.jsonFile)) as T)
      .shift();
  }

  private generateCodemodel(): NativeCodemodel | undefined {
    const codemodel = this.readCodemodel(this.index.reply);
    this.readTarget(codemodel);
    return codemodel;
  }

  private readCodemodel(reply?: Reply): NativeCodemodel | undefined {
    if (!reply || !reply['codemodel-v2']) {
      this._log.warn('Failed to generate CMake code mode. The native code will skip compiling.');
      return undefined;
    }
    const codemodelV2 = reply['codemodel-v2'];
    const file = codemodelV2?.jsonFile;
    if (!file) {
      return undefined;
    }
    const jsonFile = path.resolve(this.reply, file);
    return getJson5Obj(jsonFile) as NativeCodemodel;
  }

  private readIndex(): NativeCxxIndex {
    if (!fsExtra.existsSync(this.reply)) {
      this._log.printErrorExit('CMAKE_TASK_EXECUTION_FAILED');
    }
    const files: string[] = fsExtra.readdirSync(this.reply);
    const indexJson = files.find((value) => value.startsWith('index-'));
    if (!indexJson) {
      this._log.printErrorExit(
        'CMAKE_FILE_API_PARSE_FAILED',
        [this.reply],
        [[this.reply]]
      );
    }
    return getJson5Obj(path.resolve(this.reply, indexJson!));
  }

  private readTarget(codemodel?: NativeCodemodel): void {
    codemodel?.configurations?.forEach((configuration) => {
      if (!configuration.targets) {
        return;
      }
      for (let i = 0; i < configuration.targets?.length; i++) {
        const target = configuration.targets[i];
        const jsonFile = target.jsonFile;
        if (!jsonFile) {
          return;
        }
        configuration.targets[i] = getJson5Obj(path.resolve(this.reply, jsonFile)) as NativeTarget;
      }
    });
  }
}
